﻿using System.Collections.Generic;
using System.Reflection;
using System.IO;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Text.RegularExpressions;
using System;
#if UNITY_EDITOR
using UnityEditor;
#endif

/*
Unity通用2D游戏开发工具
本工具为 @漏了的水缸 个人制作并使用，未经允许请勿用于商业用途
*/

/*
该工具实现的功能：
：向量计算，随机数等常用功能
：对象池功能，帮助开发者简单的管理场景对象
: Resources资源操作，获取资源
：文件操作，存档读档操作
：按键重载，需要时直接修改Key值从而重定向按键输入
*/

/*
使用using static WaterCylinder;导入该工具
对象池功能在当前场景（scene）中含有名为Pool并装载了ObjectPools组件的对象时自动启用
*/


public class WaterCylinder : MonoBehaviour
{   
    /// <summary>
    /// 鼠标位置与触屏触摸位置
    /// </summary>
    public static class Mouse{
        /// <summary>
        /// 获取鼠标位置。
        /// </summary>
        /// <returns></returns>
        public static Vector3 GetMousePosition(){
            Vector3 MousePosition = Camera.main.ScreenToWorldPoint(UnityEngine.Input.mousePosition);
            MousePosition.z = 0;
            return MousePosition;
        }
        /// <summary>
        /// 获取鼠标平面位置。
        /// </summary>
        /// <returns></returns>
        public static Vector2 GetMousePosition2D(){
            Vector2 MousePosition = Camera.main.ScreenToWorldPoint(UnityEngine.Input.mousePosition);
            return MousePosition;
        }
        /// <summary>
        /// 获取指定ID触摸位置
        /// </summary>
        /// <param name="ID">触摸ID</param>
        /// <returns></returns>
        public static Vector3 GetTouchPosition(int ID){
            Vector3 pos = new Vector2(0,0);
            foreach(Touch touch in UnityEngine.Input.touches){
                if(touch.fingerId == ID){
                    pos = touch.position;
                }
            }
            pos.z = 0;
            return pos;
        }
        /// <summary>
        /// 获取指定ID触摸平面位置
        /// </summary>
        /// <param name="ID">触摸ID</param>
        /// <returns></returns>
        public static Vector2 GetTouchPosition2D(int ID){
            return Camera.main.ScreenToWorldPoint(UnityEngine.Input.GetTouch(ID).position);
        }
        /// <summary>
        /// 当前最新按下时触摸ID
        /// </summary>
        public static int NewDownTouch = 0;
        /// <summary>
        /// 更新并获取当前最新按下时触摸ID
        /// </summary>
        /// <returns></returns>
        public static int GetNewDownTouch(){//最新的触摸点的ID
            if(UnityEngine.Input.touchCount > 0){
                foreach(Touch t in UnityEngine.Input.touches){
                    if(t.phase == TouchPhase.Began){
                        NewDownTouch = t.fingerId;
                        return t.fingerId;
                    }
                }
                return NewDownTouch;
            }else{
                return NewDownTouch;
            }
        }
        /// <summary>
        /// 当前最新松开时触摸ID
        /// </summary>
        public static int NewUpTouch = 0;
        /// <summary>
        /// 更新并获取当前最新松开时触摸ID
        /// </summary>
        /// <returns></returns>
        public static int GetNewUpTouch(){
            if(UnityEngine.Input.touchCount > 0){
                foreach(Touch t in UnityEngine.Input.touches){
                    if(t.phase == TouchPhase.Ended){
                        NewUpTouch = t.fingerId;
                        return t.fingerId;
                    }
                }
                return NewUpTouch;
            }else{
                return NewUpTouch;
            }
        }
        /// <summary>
        /// 是否有触摸按下
        /// </summary>
        /// <returns></returns>
        public static bool TouchDown(){
            if(UnityEngine.Input.touchCount > 0){
                foreach(Touch t in UnityEngine.Input.touches){
                    if(t.phase == TouchPhase.Began){
                        return true;
                    }
                }
                return false;
            }
            return false;
        }
        /// <summary>
        /// 是否有触摸松开
        /// </summary>
        /// <returns></returns>
        public static bool TouchUp(){
            if(UnityEngine.Input.touchCount > 0){
                foreach(Touch t in UnityEngine.Input.touches){
                    if(t.phase == TouchPhase.Ended){
                        return true;
                    }
                }
                return false;
            }
            return false;
        }
    }

    /// <summary>
    /// 场景操作
    /// </summary>
    public static class Scene{
        /// <summary>
        /// 切换（加载）场景
        /// </summary>
        /// <param name="name"></param>
        public static void ChangeScene(string name){
            SceneManager.LoadScene(name);
        }
        /// <summary>
        /// 获取当前场景
        /// </summary>
        /// <returns></returns>
        public static string SceneNow(){
            string s = SceneManager.GetActiveScene().name;
            return s;
        }
    }

    /// <summary>
    /// 物体操作
    /// </summary>
    public static class Object{
        /// <summary>
        /// 通过Tag获取子物体，获取第一个。
        /// </summary>
        /// <param name="obj">父物体</param>
        /// <param name="tag">Tag</param>
        /// <returns></returns>
        public static GameObject FindChildByTag(GameObject obj, string tag){
            foreach(Transform item in obj.transform){
                if(item.gameObject.tag == tag)return item.gameObject;
            }
            return null;
        }
        /// <summary>
        /// 通过名字获取子物体。
        /// </summary>
        /// <param name="obj">父物体</param>
        /// <param name="name">Tag</param>
        /// <returns></returns>
        public static GameObject FindChildByName(GameObject obj, string name){
            foreach(Transform item in obj.transform){
                if(item.gameObject.name == name)return item.gameObject;
            }
            return null;
        }

        //物体生成与销毁

        /// <summary>
        /// <para>通过prefab生成物体到当前场景中，</para>
        /// <para>场景中有Pool物体时将生成的物体存储到对象池中。</para>
        /// </summary>
        /// <param name="prefab"></param>
        /// <returns></returns>
        public static GameObject Creat(GameObject prefab){
            GameObject obj = Instantiate(prefab) as GameObject;

            //对象池功能
            GameObject pools_obj;
            if(pools_obj = GameObject.Find("Pool")){
                ObjectPools pools = pools_obj.GetComponent<ObjectPools>();
                pools.Add(obj);
            }

            return obj;
        }
        /// <summary>
        /// 通过组件生成物体到当前场景中，有对象池效果
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T Creat<T>(T obj) where T : MonoBehaviour{
            return Creat(obj.gameObject).GetComponent<T>();
        }
        /// <summary>
        /// <para>销毁指定的物体，</para>
        /// <para>场景中有Pool物体时将指定的物体从对象池中移除。</para>
        /// </summary>
        /// <param name="prefab"></param>
        /// <returns></returns>
        public static bool Delete(GameObject obj){//销毁物体
            if(obj){

                //对象池功能
                GameObject pools_obj;
                if(pools_obj = GameObject.Find("Pool")){
                    ObjectPools pools = pools_obj.GetComponent<ObjectPools>();
                    pools.Del(obj);
                }

                Destroy(obj);
                return true;
            }else{
                UnityEngine.Debug.Log("删除无效");
                return false;
            }
        }

        /// <summary>
        /// <para>通过prefab和生成位置生成物体到当前场景中，</para>
        /// <para>场景中有Pool物体时将生成的物体存储到对象池中。</para>
        /// </summary>
        /// <param name="prefab"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        public static GameObject Creat(GameObject prefab, Vector2 position){//在位置上创建物体
            GameObject obj = Creat(prefab);
            obj.GetComponent<Transform>().position = position;
            return obj;   
        }
        /// <summary>
        /// <para>通过组件和生成位置生成物体到当前场景中，</para>
        /// <para>场景中有Pool物体时将生成的物体存储到对象池中。</para>
        /// </summary>
        /// <param name="prefab"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        public static T Creat<T>(T obj, Vector2 position)where T : MonoBehaviour{//在位置上创建物体
            return Creat(obj.gameObject, position).GetComponent<T>();   
        }
        /// <summary>
        /// <para>通过prefab和父对象及相对位置生成物体到当前场景中，</para>
        /// <para>场景中有Pool物体时将生成的物体存储到对象池中。</para>
        /// </summary>
        /// <param name="prefab"></param>
        /// <param name="parent"></param>
        /// <param name="localPosition"></param>
        /// <returns></returns>
        public static GameObject Creat(GameObject prefab, Transform parent, Vector2 localPosition){//在相对位置上创建物体
            GameObject obj = Creat(prefab);
            obj.GetComponent<Transform>().parent = parent;
            obj.GetComponent<Transform>().localPosition = localPosition;
            return obj;
        }
        
    }

    /// <summary>
    /// 向量计算
    /// </summary>
    public static class Vector{
        /// <summary>
        /// 默认为上方向的旋转
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        public static Vector2 Rotate(float angle){//默认为上方向的旋转
            float tx = Mathf.Sin(angle*Mathf.Deg2Rad);
            float ty = Mathf.Cos(angle*Mathf.Deg2Rad);
            return new Vector2(tx,ty);
        }
        /// <summary>
        /// 自定义基础向量的旋转
        /// </summary>
        /// <param name="toward"></param>
        /// <param name="angle"></param>
        /// <returns></returns>
        public static Vector2 Rotate(Vector2 toward, float angle){//自定义基础向量
            float tx = toward.x*Mathf.Cos(angle*Mathf.Deg2Rad)+toward.y*Mathf.Sin(angle*Mathf.Deg2Rad);
            float ty = -toward.x*Mathf.Sin(angle*Mathf.Deg2Rad)+toward.y*Mathf.Cos(angle*Mathf.Deg2Rad);
            return new Vector2(tx,ty);
        }
        /// <summary>
        /// 从向量Begin到End的角度，含有正负。
        /// </summary>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static float Angle(Vector2 begin, Vector2 end){//从向量Begin到End的角度，含有正负。
            float angle = Vector2.Angle(begin, end);
            Vector3 cross = Vector3.Cross(begin, end);
            if(cross.z > 0)return angle;
            else return -angle;
        }
    }
    
    /// <summary>
    /// 数学工具
    /// </summary>
    public static class Math{
        /// <summary>
        /// 生成a-b之间的随机数，不包含ab。
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static float Range(float a, float b){
            UnityEngine.Random.InitState((int)System.DateTime.Now.Ticks);
            return UnityEngine.Random.Range(a,b);
        }
        
        /// <summary>
        /// 获取两个向量的中间向量
        /// </summary>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <param name="rate">中间向量相对位置的比例</param>
        /// <returns></returns>
        public static Vector2 Lerp(Vector2 begin, Vector2 end, float rate = 0.5f){
            Vector2 os = (end - begin) * rate;
            return begin + os;
        }

        /// <summary>
        /// 检查两个向量是否接近
        /// </summary>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <param name="rate"></param>
        /// <returns></returns>
        public static bool Approach(Vector2 begin, Vector2 end, float rate = 0.01f){
            return Vector2.Distance(begin, end) < rate;
        }
        
        /// <summary>
        /// 检查两个浮点数是否接近
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="rate"></param>
        /// <returns></returns>
        public static bool Approach(float a, float b, float rate = 0.01f){
            return Mathf.Abs(a - b) < rate;
        }

        /// <summary>
        /// 洗牌算法根据种子值打乱一个int集合
        /// </summary>
        /// <param name="array"></param>
        /// <param name="seed"></param>
        public static List<int> ShuffleArray(List<int> array, int seed = 0){
            if(seed == 0){
                seed = (int)Range(1,1000000);
            }
            System.Random rng = new System.Random(seed);  
            for (int i = array.Count - 1; i > 0; i--){  
                // 生成一个0到i之间的随机索引  
                int j = rng.Next(i + 1);  
                // 交换元素array[i]和array[j]  
                int temp = array[i];  
                array[i] = array[j];  
                array[j] = temp;  
            }
            return array;  
        }  
    }

    /// <summary>
    /// 获取资源
    /// </summary>
    public static class Resource{
            public static Dictionary<string, UnityEngine.Object> _resources = new Dictionary<string, UnityEngine.Object>();
        
        /// <summary>
        /// 从Resources文件夹里加载资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="_name"></param>
        /// <returns></returns>
        public static T GetResources<T>(string _name) where T : UnityEngine.Object{
            lock(_resources)if(!_resources.ContainsKey(_name)){
                T obj = UnityEngine.Resources.Load(_name) as T;
                _resources.Add(_name, obj);
            }
            lock(_resources)if(_resources[_name] == null){
                _resources[_name] = UnityEngine.Resources.Load<T>(_name);
            }
            lock(_resources)if(_resources[_name] != null){
                return _resources[_name] as T;
            }else{
                return null;
            }
            
        }
        /// <summary>
        /// 从Resources文件夹里异步加载资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="_name"></param>
        /// <returns>异步包，可以获取资源加载结果以及加载进度</returns>
        public static ResourceRequest LoadResourceAsync<T>(string _name) where T : UnityEngine.Object{
            ResourceRequest q = UnityEngine.Resources.LoadAsync<T>(_name);
            q.completed += (a) => {
                if(a.isDone){
                    T obj = (T) q.asset;
                    lock(_resources)if(_resources.ContainsKey(_name)){
                        _resources[_name] = obj;
                    }else{
                        _resources.Add(_name, obj);
                    }
                }
            };
            return q;
        }

        /// <summary>
        /// 释放所有资源
        /// </summary>
        public static void UnLoadResources(){
            foreach(KeyValuePair<string, UnityEngine.Object> item in _resources){
                UnityEngine.Resources.UnloadAsset(item.Value);
            }
        }
        
        /// <summary>
        /// 从Resources中加载prefab。
        /// </summary>
        /// <param name="_name"></param>
        /// <returns></returns>
        public static GameObject GetPrefab(string _name){
            return GetResources<GameObject>(_name);
        }
        /// <summary>
        /// 从Resources中异步加载物体资源，加载成功的资源可以使用GetPrefab获取
        /// </summary>
        /// <param name="_name"></param>
        /// <returns>异步包，可以获取资源加载结果以及加载进度</returns>
        public static ResourceRequest LoadPrefabAsync(string _name){
            return LoadResourceAsync<GameObject>(_name);
        }
        /// <summary>
        /// 从Resources中加载精灵图片。
        /// </summary>
        /// <param name="_name"></param>
        /// <returns></returns>
        public static Sprite GetSprite(string _name){
            return GetResources<Sprite>(_name);
        }
        /// <summary>
        /// 从Resources中异步加载精灵资源，加载成功的资源可以使用GetSprite获取
        /// </summary>
        /// <param name="_name"></param>
        /// <returns>异步包，可以获取资源加载结果以及加载进度</returns>
        public static ResourceRequest LoadSpriteAsync(string _name){
            return LoadResourceAsync<Sprite>(_name);
        }

        /// <summary>
        /// 释放所有未使用的资源
        /// </summary>
        public static void UnLoadAllResources(){
            UnityEngine.Resources.UnloadUnusedAssets();
        }

    }

    /// <summary>
    /// Debug相关
    /// </summary>
    public static class Debug{
        public static void Log(string context){
            UnityEngine.Debug.Log(context);
        }
        public static string ListToString<T>(List<T> list){
            string res = list.ToString() + "[";
            foreach(var item in list){
                res += "(" + item.ToString() + ")";
            }
            return res + "]";
        }

        public static string DicToString<T1,T2>(Dictionary<T1,T2> dic){
            string res = dic.ToString() + "[";
            foreach(var item in dic){
                res += "(K: " + item.Key + " V: " + item.Value + ")";
            }
            return res + "]";
        }
    }

    /// <summary>
    /// 矩形相关
    /// </summary>
    public static class Rect{
        /// <summary>
        /// 计算点是否在矩阵里（仅计算二维坐标）。
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="rect"></param>
        /// <returns></returns>
        public static bool PosInRect(Vector2 pos, UnityEngine.Rect rect){
            if(pos.x > rect.x + rect.width / 2
            || pos.x < rect.x - rect.width / 2
            || pos.y > rect.y + rect.height / 2
            || pos.y < rect.y - rect.height / 2){
                return false;
        }else{
                return true;
            }
        }
    }

    /// <summary>
    /// Sprite与Texture2D相互转化
    /// </summary>
    public static class SpriteTexture{
        /// <summary>
        /// 将sprite转化为texture
        /// </summary>
        /// <param name="sprite"></param>
        /// <returns></returns>
        public static Texture2D Sprite2Texture2D(Sprite sprite){
            Texture2D t2d = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height);
            var pixels = sprite.texture.GetPixels(
                (int)sprite.textureRect.x,
                (int)sprite.textureRect.y,
                (int)sprite.textureRect.width,
                (int)sprite.textureRect.height);
            t2d.SetPixels(pixels);
            t2d.Apply();
            return t2d;
        }

        /// <summary>
        /// 将texture2D转化为sprite
        /// </summary>
        /// <param name="t2d"></param>
        /// <returns></returns>
        public static Sprite Texture2D2Sprite(Texture2D t2d){
            Sprite s= Sprite.Create(t2d, new UnityEngine.Rect(0, 0, t2d.width, t2d.height), Vector2.zero);
            return s;
        }
    }

    /// <summary>
    /// 文件操作
    /// </summary>
    public static class File{
        /// <summary>
        /// 游戏目录下config文件夹路径
        /// </summary>
        /// <returns></returns>C
        public static string dataPath{
            get{
                return Application.dataPath;
            }
        }

        /// <summary>
        /// 用户目录路径
        /// </summary>
        /// <returns></returns>
        public static string userPath{
            get{
                return Application.persistentDataPath;
            }
        }

        /// <summary>
        /// 读取文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns>文件字符流对象</returns>
        public static StreamReader FileRead(string path, bool append = true){//读取文件
            try{
                if(!System.IO.File.Exists(path)){
                    string dir = Path.GetDirectoryName(path);
                    if(!Directory.Exists(dir)){
                        Directory.CreateDirectory(dir);
                    }
                    System.IO.File.Create(path);
                    Debug.Log($"获取读取文件流异常，文件{path}不存在或文件夹不存在，已自动创建空白文件");
                }else{
                    return new StreamReader(path, append);
                }
            }catch(Exception e){
                Debug.Log($"读取文件异常{e.Message}");
            }
            return null;
        }
        
        /// <summary>
        /// 写入文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns>文件字符流对象</returns>
        public static StreamWriter FileWrite(string path, bool append = true){
            try{
                if(!System.IO.File.Exists(path)){
                    string dir = Path.GetDirectoryName(path);
                    if(!Directory.Exists(dir)){
                        Directory.CreateDirectory(dir);
                    }
                    System.IO.File.Create(path);
                    Debug.Log($"获取写入文件流异常，文件{path}不存在或文件夹不存在，已自动创建空白文件");
                }else{
                    return new StreamWriter(path, append);
                }
            }catch(Exception e){
                Debug.Log($"写入文件异常{e.Message}");
            }
            return null;
        }

        /// <summary>
        /// 读取文件的所有内容
        /// </summary>
        /// <param name="reader"></param>
        /// <returns>文件内容字符串</returns>
        public static string ReadAll(StreamReader reader){
            string str = "";
            if(reader != null){
                str = reader.ReadToEnd();
                reader.Close();
            }
            return str;
        }
        /// <summary>
        /// 读取文件的所有内容
        /// </summary>
        /// <param name="path"></param>
        /// <returns>文件内容字符串</returns>
        public static string ReadAll(string path){
            StreamReader reader = FileRead(path);
            return ReadAll(reader);
        }

        /// <summary>
        /// 写入文件内容
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="str">写入内容</param>
        /// <returns>是否写入成功</returns>
        public static bool WriteAll(StreamWriter writer, string str){
            if(writer != null){
                writer.Write(str);
                writer.Close();
                return true;
            }else{
                return false;
            }
        }
        /// <summary>
        /// 写入文件内容
        /// </summary>
        /// <param name="path"></param>
        /// <param name="str">写入内容</param>
        /// <returns>是否写入成功</returns>
        public static bool WriteAll(string path, string str){
            using StreamWriter writer = FileWrite(path);
            return WriteAll(writer, str);
        }

        

    }

    /// <summary>
    /// 输入
    /// </summary>
    public static class Input{
        public static bool Check(string key){
            if(Tool.StrInclude(key, "mouse")){
                if(Tool.StrInclude(key, "left")){//左键触发
                    return UnityEngine.Input.GetMouseButtonDown(0);
                }else if(Tool.StrInclude(key, "right")){//右键触发
                    return UnityEngine.Input.GetMouseButtonDown(1);
                }else{
                    Debug.Log("WaterCylinder输入检测异常: 鼠标输入参数错误");
                    return false;
                }
            }else{
                return UnityEngine.Input.GetKey(key);//键盘按键触发
            }
        }
        /// <summary>
        /// 左键按下
        /// </summary>
        /// <returns></returns>
        public static bool InputOperaDown{
            get{
                if(UnityEngine.Input.GetMouseButtonDown(0))return true;
                else return false;
            }
        }
        /// <summary>
        /// 左键按住
        /// </summary>
        /// <returns></returns>
        public static bool InputOpera{
            get{
                if(UnityEngine.Input.GetMouseButton(0))return true;
                else return false;
            }
        }
        /// <summary>
        /// 左键弹起
        /// </summary>
        /// <returns></returns>
        public static bool InputOperaUp{
            get{
                if(UnityEngine.Input.GetMouseButtonUp(0))return true;
                else return false;
            }
        }
        /// <summary>
        /// 右键按下
        /// </summary>
        /// <returns></returns>
        public static bool InputChoiceDown{
            get{
                if(UnityEngine.Input.GetMouseButtonDown(1))return true;
                else return false;
            }
        }
        /// <summary>
        /// 右键按住
        /// </summary>
        /// <returns></returns>
        public static bool InputChoice{
            get{
                if(UnityEngine.Input.GetMouseButton(1))return true;
                else return false;
            }
        }
        /// <summary>
        /// 右键谈起
        /// </summary>
        /// <returns></returns>
        public static bool InputChoiceUp{
            get{
                if(UnityEngine.Input.GetMouseButtonUp(1))return true;
                else return false;
            }
        }
        /// <summary>
        /// 滚轮上
        /// </summary>
        /// <returns></returns>
        public static bool InputWheelUp{
            get{
                if(UnityEngine.Input.GetAxis("Mouse ScrollWheel") > 0)return true;
                else return false;
            }
        }
        /// <summary>
        /// 滚轮下
        /// </summary>
        /// <returns></returns>
        public static bool InputWheelDown{
            get{
                if(UnityEngine.Input.GetAxis("Mouse ScrollWheel") < 0)return true;
                else return false;
            }
        }

        /// <summary>
        /// 左键按键
        /// </summary>
        public static string KeyLeft = "a";
        /// <summary>
        /// 右键按键
        /// </summary>
        public static string KeyRight = "d";
        /// <summary>
        /// 上键按键
        /// </summary>
        public static string KeyUp = "w";
        /// <summary>
        /// 下键按键
        /// </summary>
        public static string KeyDown = "s";
        /// <summary>
        /// 重新装填按键
        /// </summary>
        public static string KeyChange = "r";
        /// <summary>
        /// 跳跃按键
        /// </summary>
        public static string KeyBurst = "space";

        

        //键盘方向键输入队列

        /// <summary>
        /// 方向键输入列表
        /// </summary>
        public static List<string> KeyList = new List<string>();

        /*
        输入队列的队列尾部的值是最后输入
        */
        /// <summary>
        /// 获取方向键输入，输入结果存入输入列表中
        /// </summary>
        public static void InputKeyList(){//输入队列，放在Update里以持续进行队列运算
            if(InputLeftDown)KeyList.Add(KeyLeft);
            if(InputRightDown)KeyList.Add(KeyRight);
            if(InputUpDown)KeyList.Add(KeyUp);
            if(InputDownDown)KeyList.Add(KeyDown);

            if(InputLeftUp)KeyList.Remove(KeyLeft);
            if(InputRightUp)KeyList.Remove(KeyRight);
            if(InputUpUp)KeyList.Remove(KeyUp);
            if(InputDownUp)KeyList.Remove(KeyDown);

            //输入补正
            if(InputLeft){
                if(!KeyList.Contains(KeyLeft)){
                    KeyList.Add(KeyLeft);
                }
            }else{
                if(KeyList.Contains(KeyLeft)){
                    KeyList.Remove(KeyLeft);
                }
            }
            if(InputRight){
                if(!KeyList.Contains(KeyRight)){
                    KeyList.Add(KeyRight);
                }
            }else{
                if(KeyList.Contains(KeyRight)){
                    KeyList.Remove(KeyRight);
                }
            }
            if(InputUp){
                if(!KeyList.Contains(KeyUp)){
                    KeyList.Add(KeyUp);
                }
            }else{
                if(KeyList.Contains(KeyUp)){
                    KeyList.Remove(KeyUp);
                }
            }
            if(InputDown){
                if(!KeyList.Contains(KeyDown)){
                    KeyList.Add(KeyDown);
                }
            }else{
                if(KeyList.Contains(KeyDown)){
                    KeyList.Remove(KeyDown);
                }
            }
        }

        /// <summary>
        /// 获取倒数第id个key的值，放在Update里以持续进行队列运算
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static string GetKeyInList(int id){//获取倒数第id个key的值，放在Update里以持续进行队列运算
            InputKeyList();
            string key = "";
            if(KeyList.Count - id >= 0)
                key = KeyList[KeyList.Count - id];
            return key;
        }

        /// <summary>
        /// 获取四方向方向输入结果。
        /// </summary>
        /// <returns></returns>
        public static Vector2 GetStraight(){//获取直边
            string key = GetKeyInList(1);
            Vector2 velocity = new Vector2(0,0);
            if(key != ""){
                if(key == KeyUp){
                    velocity = new Vector2(0,1);
                }else if(key == KeyDown){
                    velocity = new Vector2(0,-1);
                }else if(key == KeyLeft){
                    velocity = new Vector2(-1,0);
                }else if(key == KeyRight){
                    velocity = new Vector2(1,0);
                }
            }
            return velocity;
        }

        /// <summary>
        /// 获取八方向方向输入结果。
        /// </summary>
        /// <returns></returns>
        public static Vector2 GetOblique(){//获取斜边。2D移动的终极解决方案，直接放在Updata里就能获得当前准确的velocity
            string key = GetKeyInList(1);
            Vector2 velocity = GetStraight();
            if(KeyList.Count >= 2 && key != ""){
                for(int i = KeyList.Count - 2; i >= 0; i--){
                    key = KeyList[i];
                    if(velocity.x != 0){
                        if(key == KeyUp){
                            velocity.y = 1;
                            break;
                        }else if(key == KeyDown){
                            velocity.y = -1;
                            break;
                        }
                    }else if(velocity.y != 0){
                        if(key == KeyRight){
                            velocity.x = 1;
                            break;
                        }else if(key == KeyLeft){
                            velocity.x = -1;
                            break;
                        }
                    }
                }
            }
            return velocity;
        }


        //键盘输入
        

        public static bool InputLeftDown{
            get{
                if(UnityEngine.Input.GetKeyDown(KeyLeft))return true;
                else return false;
            }
        }
        public static bool InputLeft{
            get{
                if(UnityEngine.Input.GetKey(KeyLeft))return true;
                else return false;
            }
        }
        public static bool InputLeftUp{
            get{
                if(UnityEngine.Input.GetKeyUp(KeyLeft))return true;
                else return false;
            }
        }
        public static bool InputRightDown{
            get{
                if(UnityEngine.Input.GetKeyDown(KeyRight))return true;
                else return false;
            }
        }
        public static bool InputRight{
            get{
                if(UnityEngine.Input.GetKey(KeyRight))return true;
                else return false;
            }
        }
        public static bool InputRightUp{
            get{
                if(UnityEngine.Input.GetKeyUp(KeyRight))return true;
                else return false;
            }
        }
        public static bool InputDownDown{
            get{
                if(UnityEngine.Input.GetKeyDown(KeyDown))return true;
                else return false;
            }
        }
        public static bool InputDown{
            get{
                if(UnityEngine.Input.GetKey(KeyDown))return true;
                else return false;
            }
        }
        public static bool InputDownUp{
            get{
                if(UnityEngine.Input.GetKeyUp(KeyDown))return true;
                else return false;
            }
        }
        public static bool InputUpDown{
            get{
                if(UnityEngine.Input.GetKeyDown(KeyUp))return true;
                else return false;
            }
        }
        public static bool InputUp{
            get{
                if(UnityEngine.Input.GetKey(KeyUp))return true;
                else return false;
            }
        }
        public static bool InputUpUp{
            get{
                if(UnityEngine.Input.GetKeyUp(KeyUp))return true;
                else return false;
            }
        }
        public static bool InputChangeWeapon{
            get{
                if(UnityEngine.Input.GetKeyUp(KeyChange))return true;
                else return false;
            }
        }
        public static bool InputBurstDown{
            get{
                if(UnityEngine.Input.GetKeyDown(KeyBurst))return true;
                else return false;
            }
        }
        public static bool InputBurst{
            get{
                if(UnityEngine.Input.GetKey(KeyBurst))return true;
                else return false;
            }
        }
        public static bool InputBurstUp{
            get{
                if(UnityEngine.Input.GetKeyUp(KeyBurst))return true;
                else return false;
            }
        }
    }

    /// <summary>
    /// 存档
    /// </summary>
    public static class Save{
        /// <summary>
        /// 存储数据到指定容器
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="target">容器名称</param>
        /// <param name="data"></param>
        public static void SaveSet<T>(string target, T data){
            object _data = data;
            if(data is int){
                PlayerPrefs.SetInt(target, (int)_data);
            }else if(data is float){
                PlayerPrefs.SetFloat(target, (float)_data);
            }else if(data is string){
                PlayerPrefs.SetString(target, (string)_data);
            }
        }
        /// <summary>
        /// 从指定的容器里读取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="target">容器名称</param>
        /// <returns></returns>
        public static object SaveGet<T>(string target){
            T data = default;
            object _data = data;
            if(_data is int){
                _data = PlayerPrefs.GetInt(target);
            }else if(_data is float){
                _data = PlayerPrefs.GetFloat(target); 
            }else if(_data is string){
                _data = PlayerPrefs.GetString(target); 
            }
            return _data;
        }
    }
    

    public static class Tool{
        /// <summary>
        /// Int值转化为枚举
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="num"></param>
        /// <returns></returns>
        public static T Int2Enum<T>(int num) where T : Enum{
            return (T)Enum.Parse(typeof(T), num.ToString());
        }

        /// <summary>
        /// 判断字符串是否包含某字符串，无视大小写
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool StrInclude(string org, string str){
            return org.IndexOf(str,StringComparison.OrdinalIgnoreCase) >= 0;
        }
    }

    /// <summary>
    /// 编辑器相关
    /// </summary>
    public static class Editor{
        #if UNITY_EDITOR
        /// <summary>
        /// 获取操作的属性对象
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        public static object GetProperty(SerializedProperty property){
            try{
                object value = property.serializedObject.targetObject;
                string[] names = property.propertyPath.Split(".");
                
                Type type = value.GetType();
                FieldInfo info = type.GetField(names[0]);
                
                foreach(string name in names){
                    
                    if(name.Contains("data")){
                        
                        Match match = Regex.Match(name, @"data\[([^\]]+)\]");
                        int id = int.Parse(match.Groups[1].Value);
                        PropertyInfo pinfo = type.GetProperty("Item");
                        value = pinfo.GetValue(value, new object[]{id});
                        type = value.GetType();
                        
                    }else if(name.Contains("Array")){
                        
                        continue;//Array不是一个有效的路径
                        
                    }else{
                        
                        info = type.GetField(name);
                        value = info.GetValue(value);
                        type = value.GetType();
                        
                    }
                    
                }
                return value;
            }catch(Exception e){
                UnityEngine.Debug.LogError(e);
                return null;
            }
        }   
        
        #endif
    }
    
}


//流程类，附带单例效果。
/*
这是个父类，游戏流程直接继承该类即可，继承方式为：
class Game: Process<Game>
使用方法：
一：含有Instance单例，外部对象可直接访问。
二：流程控制中枢：
    在子类里定义名为“Process” + 流程序号的方法,即可。列如：
    void process1{
        Next();
    }
    void process2{
        Next();
    }
    在方法中使用Next()来跳转到下一个流程，或者使用Next(int)跳转到指定流程。
    Wait(float, function=)方法可以暂停检测，指定时间之后跳转到下一个流程,也可以一段时间后运行特定方法。
    流程方法的最后添加End()。
    暂时就这些功能。

需要注意的是，Process后的数字和Global.A是对应的。
*/
/*
public class GameProcess<T> : MonoBehaviour where T: GameProcess<T>, new()
{
    static T instance;
    public static T Instance{
        get{
            if(instance == null)instance = FindObjectOfType<T>() as T;
            return instance;
        }
    }

    public bool pause = false;

    public bool processEnd = true;

    public int a = 0;

    //不删除功能，暂时不用
   /* void Awake(){
        DontDestroyOnLoad(this);
        if(FindObjectOfType<T>() != this){
           Unity2dGeneralDevelopmentTool.Delete(this.gameObject);
        }
    }*//*
/*
    protected void Next(){
        a = a + 1;
        End();
        pause = false;
    }
    protected void Next(int target){
        a = target;
        End();
        pause = false;
    }
    protected void End(){
        processEnd = true;
        Global.A = a;
    }
    protected void Wait(float time, string function = ""){
        if(!pause){
            pause = true;
            if(function == ""){
                Invoke("Next", time);
            }else{
                Invoke(function, time);
            }
            
        }
    }

    protected int process(){
        a = Global.A;
        if(processEnd && !pause){
            processEnd = false;
            Invoke("Process" + a, 0);
        }
        return a;
    }

    void Update(){
        process();
    }
}
*/